package com.aldobucchi.graph.query
{
	
	import flash.events.Event;
	
	import mx.collections.ArrayCollection;
	import mx.collections.IList;
	
	import com.aldobucchi.core.dependency.DependencySpec;
	import com.aldobucchi.core.dependency.EventDispatcherWithDependenciesBase;
	import com.aldobucchi.graph.restrictionTree.RTVarNode;
	import com.aldobucchi.tree.TreeEvent;
	import com.aldobucchi.x.flash.events.EventListenerSpec;


	public class NodeList extends EventDispatcherWithDependenciesBase
	{
		
		
		//////////////////////////////////////////////
		// executing
		//////////////////////////////////////////////		
		
		private var _executing:Boolean = false;
		[Bindable("executingChanged")]
		public function get executing( ):Boolean
		{
			return _executing;
		}
		
		
		//////////////////////////////////////////////
		// varNode
		//////////////////////////////////////////////
		private var els:Array = [
			new EventListenerSpec( TreeEvent.TREE_CHANGED, varNode_treeChanged )
		];
		
		private var varNodeSpec:DependencySpec = new DependencySpec( "varNode", "varNodeChanged", els );
		[Bindable("varNodeChanged")]
		public function get varNode( ):RTVarNode
		{
			return dh.getDependencyValue( varNodeSpec ) as RTVarNode;
		}
		
		public function set varNode( v:RTVarNode ):void
		{
			dh.setDependencyValue( varNodeSpec, v );
		}
		
		
		//////////////////////////////////////////////
		// limit
		//////////////////////////////////////////////		
		
		private var limitSpec:DependencySpec = new DependencySpec( "limit", "limitChanged", null, false, -1 );
		[Bindable("limitChanged")]
		public function get limit( ):int
		{
			return dh.getDependencyValue( limitSpec );
		}
		public function set limit( v:int ):void
		{
			dh.setDependencyValue( limitSpec, v );
		}
		
		
		//////////////////////////////////////////////
		// offset
		//////////////////////////////////////////////		
		
		private var offsetSpec:DependencySpec = new DependencySpec( "offset", "offsetChanged", null, false, -1 );
		[Bindable("offsetChanged")]
		public function get offset( ):int
		{
			return dh.getDependencyValue( offsetSpec );
		}
		public function set offset( v:int ):void
		{
			dh.setDependencyValue( offsetSpec, v );
		}
		
		
		
		//////////////////////////////////////////////
		// list
		//////////////////////////////////////////////		
		private var _list:ArrayCollection = new ArrayCollection( );
		[Bindable("listChanged")]
		public function get list( ):IList
		{
			return _list;
		}		
		
		

		//////////////////////////////////////////////
		// totalCount
		//////////////////////////////////////////////		
		private var _totalCount:int;
		[Bindable("totalCountChanged")]
		public function get totalCount( ):int
		{
			return _totalCount;
		}
		
		
		
		/**
		 * The query used to get the actual items
		 */		
		private var dataQuery	:Query = null;


		/**
		 * The query used to count the total number of items
		 */
		private var countQuery	:Query = null;

		
		
		override protected function dependenciesUpdated( ):void
		{
			refresh( );		
		}
		
		
		private function varNode_treeChanged( event:TreeEvent ):void
		{
			refresh( );		
		}
		
		


		
		private function refresh( ):void
		{
			refreshData( );
			refreshCount( );
		}
		
		
		
		private function refreshData( ):void
		{
		
			var q:Query = supercedeQuery( "dataQuery", 8 );
			
			if ( varNode == null )
				return;
			
			q.restrictionTreeRoot 	= varNode.top as RTVarNode;
			q.selectVar 			= varNode;
			q.distinct 				= true;
			
			if ( offset != -1 )
				q.offset = offset;			
			
			if ( limit != -1 )
				q.limit = limit;
		
			q.execute( );
			
			
		}		



		private function refreshCount( ):void
		{
			var q:Query = supercedeQuery( "countQuery", 7 );
			
			if ( varNode == null )
				return;
			
			q.restrictionTreeRoot = varNode.top as RTVarNode;
			q.selectVar = varNode;	
			q.aggregate = "COUNT";
			
			q.execute( );
		}




		private function query_result( event:QueryEvent ):void
		{
			
			
			if ( event.target == dataQuery )
			{
				_list.disableAutoUpdate( );
				_list.removeAll( );								
			
				try {
				
					for each ( var term:* in event.target.result )
					{
						_list.addItem( term );
					}
				
				} catch ( e:Error ){}
			
			
				_list.enableAutoUpdate( );
			}
			else
			{
				try
				{
					_totalCount = event.target.result;
					dispatchEvent( new Event( "totalCountChanged" ) );		
				} catch( e:Error ){}
			
			}
		
		}




		private function supercedeQuery( prop:*, priority:uint=5 ):Query
		{

			var q:Query = this[ prop ] as Query;
			
			if ( q != null ) {
				q.cancel( );
				q.removeEventListener( QueryEvent.RESULT, query_result );			
			}
			
			q = new Query( );
			q.priority = priority;
			q.addEventListener( QueryEvent.RESULT, query_result );
			this[ prop ] = q;
			
			return q;
		}






		
		
		
		
	}
}